/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_Studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/


#include "车辆AI训练.h"


#include <随机数.h>
#include <面/面.h>
#include <物理/物理.h>
#include "../A_引擎/引擎.h"


//#include <ML/ML.h>

using namespace std;


static S_结构对象指针	ddpgNet[100] = {0};
static S_物体*			g射线可视模型 = 0;

static vector<vector<float32>>	g环境(100);
static vector<vector<float32>>	g操作(100);
static vector<float32>			g奖励(100);
static vector<vector<float32>>	g环境_下一次(100);

static uint32 输入维度 = 14;

void fun_车辆操控(S_Object* obj) {
	auto* 车 = dynamic_cast<S_车辆*>(obj);

	车->f_加速(g操作[obj->m_ID][0]);
	车->f_刹车(g操作[obj->m_ID][1]);
	车->f_转向(g操作[obj->m_ID][2]);
	车->f_手刹(g操作[obj->m_ID][3]);

	/*车->f_加速(0.1f);
	车->f_刹车(0.0f);
	车->f_转向(0.1f);
	车->f_手刹(0.0f);*/

}


bool f_物理碰撞回调(const S_碰撞信息& info) {
	if (info.物体A) {
		auto& name = ((S_物体*)info.物体A)->m_Name;
		if (name == L"场景") {
			//std::cout << "物体A == " << ((S_物体*)info.物体A)->m_Name << std::endl;
		}
		
	}
	if (info.物体B) {
		auto& name = ((S_物体*)info.物体B)->m_Name;
		if (name == L"场景") {
			//std::cout << "物体B == " << ((S_物体*)info.物体B)->m_Name << std::endl;
		}
	}

	//if (info.速度A > info.速度B) {
		if (info.物体A) {
			g奖励[((S_物体*)info.物体A)->m_ID] -= info.冲量*10;
		}
	//}
	//else {
		if (info.物体B) {
			g奖励[((S_物体*)info.物体B)->m_ID] -= info.冲量*10;
		}
	//}

	//std::cout << "冲量 b == " << info.冲量 << std::endl;
	return false;
	std::cout << "obj a == " << info.物体A << std::endl;
	std::cout << "obj b == " << info.物体B << std::endl;
	
	std::cout << "周期 b == " << info.周期 << std::endl;
	

	return false;
}



static uint32 间隔 = 0;
static uint32 世代 = 0;
static int64 时间 = 0;
static bool 开始添加记录 = false;

static vector<float32> 操作随机(4);
static float32 探索范围 = 1.0;
static float32 总奖励 = 0.0;

void f_渲染前更新(S_Scene* scene){
	auto car = f_get场景中车辆(scene);
	uint32 i = 0; 

	
	
	if (间隔 == 0) {
		for (auto& c : car) {
		//auto* mesh = f_from物体Mesh(g射线可视模型);
			vec3 co = c->f_getLoc();
			auto s = c->f_get速度();
			auto r = c->f_getRotVel();

		
			f_随机向量(操作随机, 4, { -探索范围, 探索范围 }, 时间);
			++时间;
		

			if (s.w > 0) {
				g奖励[c->m_ID] += s.w*0.01;
			}
			else if (s.w < 0) {
				g奖励[c->m_ID] += fabs(s.w) * 0.001;
			}
			if (fabs(s.w) < 0.05) {
				g奖励[c->m_ID] -= 0.01;
			}

			if (r.y) {
				//g奖励[c->m_ID] /= r.y*10;
			}
		
			/*auto a = f_预测动作(ddpgNet[c->m_ID], g环境[c->m_ID]);
			a[0] += 操作随机[0];
			a[1] += 操作随机[1];
			a[2] += 操作随机[2];
			a[3] += 操作随机[3];

			a[0] = DEF_Min(a[0], 0.5);
			a[0] = DEF_Max(a[0], -0.5);
		
			a[1] = DEF_Min(a[1], 0.0);
			a[1] = DEF_Max(a[1], -0.0);

			a[2] = DEF_Min(a[2], 0.0);
			a[2] = DEF_Max(a[2], -0.0);

			a[3] = DEF_Min(a[3], 0.0);
			a[3] = DEF_Max(a[3], -0.0);*/
		
		
			vector<float32> 环境(输入维度);
			g环境_下一次[c->m_ID][0] = s.x;
			g环境_下一次[c->m_ID][1] = s.y;
			g环境_下一次[c->m_ID][2] = s.z;
			g环境_下一次[c->m_ID][3] = s.w;
		
			for (uint8 j = 0; j < 10; ++j) {
				//uint32 id = (i * 10 + j) * 2;
				//f_set顶点数据(mesh, co, id);
				//f_set顶点数据(mesh, c->m_射线碰撞点[j], id+1);
				float32 l = vec_len(co - c->m_射线碰撞点[j]) / 20.0;

				g环境_下一次[c->m_ID][4+j] = l;
			}



			//if (间隔 >= 30 && 开始添加记录) {
				//std::cout << "== 记录训练数据 == " << std::endl;
			//float32 奖励 = DEF_Max(0.0, g奖励[c->m_ID]) / 100.0;
			float32 奖励 = g奖励[c->m_ID] / 1000.0;
			奖励 = DEF_Max(-1.0, 奖励);
			奖励 = DEF_Min(1.0, 奖励);
				//if (奖励 > 0.0) {
					//f_DDPG记录训练数据(ddpgNet[c->m_ID], g环境[c->m_ID], g操作[c->m_ID], 奖励, g环境_下一次[c->m_ID]);
				//}
				
			//}

			//g操作[c->m_ID] = a;
			g环境[c->m_ID] = g环境_下一次[c->m_ID];

			总奖励 += 奖励;
			


			

			
			/*if (世代 >= 100) {
				if (f_训练模型(ddpgNet[c->m_ID])) {
					探索范围 *= 0.97;

					
				}
				
				g奖励[c->m_ID] = 0.0;
			}*/


			++i;
		}
		//std::cout << "car B == " << s.x << " " << s.y << " " << s.z << std::endl;
		
	}

	
	
	++间隔;

	if (间隔 > 50) {
		间隔 = 0;
		++世代;
	}

	if (世代 > 100) {
		i = 0;
		for (auto& c : car) {
			c->f_setLocRot({ 3.0f * i - 50.0f, 2.0f, 0.0f }, { 0.0f,0.0f,0.0 });
			c->f_setVel({ 0.0f,0.0f,0.0 });
			++i;
		}
		std::cout << "总奖励 = " << 总奖励 << std::endl;
		总奖励 = 0;

		世代 = 0;
	}
	
	

	开始添加记录 = true;
	//std::cout << "car B == " << car.size() << std::endl;;
}




void f_test_车辆AI() {
	//f_initPython();

	for (uint32 i = 0; i < 100; ++i) {
		//ddpgNet[i] = f_createDDPG模型(输入维度, 4);
	}
	

	f_连接物理引擎车辆操控函数(S_框架::g_Scene, fun_车辆操控);
	f_连接渲染前更新函数(S_框架::g_Scene, (fun_渲染前更新p)f_渲染前更新);
	S_框架::g_Scene->m_Physics.m_Bullet->m_全局碰撞回调 = f_物理碰撞回调;



	/*g射线可视模型 = f_创建物体(E_物体数据::t_网格, 0, S_Core::ctx);
	auto* mesh = f_from物体Mesh(g射线可视模型);
	std::vector<vec3> v;
	f_随机向量(v, 8*2*20, { -10.0, 10.0 }, 10);
	mesh->f_fill顶点(v);
	mesh->f_fill法线(v);
	f_set物体材质(g射线可视模型, S_Core::g_线段绘制材质);*/
	//f_场景链接物体(S_Core::g_Scene, g射线可视模型);



	for (auto& e : g环境) {
		e.resize(输入维度);
	}
	for (auto& e : g操作) {
		e.resize(4);
	}
	for (auto& e : g环境_下一次) {
		e.resize(输入维度);
	}

}



